////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016-2018 Qualcomm Technologies, Inc.
// All Rights Reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  camxhal3module.cpp
/// @brief Definitions for HAL3Module class. The purpose of the HAL3Device class is to abstract camera_module_t methods. For
///        further information on the corresponding methods in the HAL3 API, please refer to hardware/hardware.h and
///        hardware/camera3.h.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "camxchicontext.h"
#include "camxcsl.h"
#include "camxentry.h"
#include "camxhal3metadatautil.h"
#include "camxhaldevice.h"
#include "camxhal3module.h"
#include "camxhal3types.h"
#include "camxhaldevice.h"
#include "camxhwcontext.h"
#include "camxincs.h"
#include "camxutils.h"
#include "chi.h"
#include "chioverride.h"
#include "g_camxversion.h"
#include "camxhal3defaultrequest.h"

CAMX_NAMESPACE_BEGIN

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Macros
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// These macros match the definitions found in hardware/camera_common.h and hardware/hardware.h
#define CAMERA_DEVICE_HALAPI_VERSION(major, minor) ((((major) & 0xFF) << 8) | ((minor) & 0xFF))
#define CAMERA_DEVICE_HALAPI_VERSION_3_3 CAMERA_DEVICE_HALAPI_VERSION(3, 3)

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HAL3Module::GetInstance
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HAL3Module *HAL3Module::GetInstance()
{
    static HAL3Module s_HAL3ModuleSingleton;
    return &s_HAL3ModuleSingleton;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HAL3Module::SetCbs
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult HAL3Module::SetCbs(
    const CameraModuleCbs *pModuleCbs)
{
    CamxResult result = CamxResultSuccess;

    m_pModuleCbs = pModuleCbs;
    m_dropCallbacks = FALSE;

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HAL3Module::SetDropCallbacks
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID HAL3Module::SetDropCallbacks()
{
    CAMX_LOG_ERROR(CamxLogGroupHAL, "We are dropping the callbacks due to error conditions!");
    m_dropCallbacks = TRUE;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// HAL3Module::SetTorchMode
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult HAL3Module::SetTorchMode(
    UINT32 logicalCameraId,
    UINT32 fwNotificationId,
    BOOL enableTorch)
{
    CamxResult result = CamxResultSuccess;

    if (m_numLogicalCameras <= logicalCameraId)
    {
        // CamxResultEInvalidArg : Camera ID is invalid
        CAMX_LOG_ERROR(CamxLogGroupHAL, "Invalid camera id: %d", logicalCameraId);
        result = CamxResultEInvalidArg;
    }
    // CamxResultENotImplemented : Camera ID does not have a torch
    /// @todo (CAMX-265) Make sure flash exists for this cameraId
    else if (TorchModeStatusNotAvailable == m_torchStatus[logicalCameraId])
    {
        // CamxResultEBusy : The camera ID was already reserved
        CAMX_LOG_ERROR(CamxLogGroupHAL, "Torch not available for camera id: %d", logicalCameraId);
        result = CamxResultEBusy;
    }
    else
    {
        TorchModeStatus torchStatus = (TRUE == enableTorch) ? TorchModeStatusAvailableOn : TorchModeStatusAvailableOff;
        HAL3Module::GetInstance()->SetTorchModeInternal(logicalCameraId, fwNotificationId, torchStatus, FALSE);
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// HAL3Module::ReserveTorchForCamera
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID HAL3Module::ReserveTorchForCamera(
    UINT32 logicalCameraId,
    UINT32 fwNotificationId)
{
    CAMX_ASSERT(logicalCameraId < m_numLogicalCameras);
    CAMX_UNREFERENCED_PARAM(fwNotificationId);

    // Make sure all flash lights are turned off to reserve the flash for camera Open
    for (UINT32 sensor = 0; sensor < m_numLogicalCameras; sensor++)
    {
        SetTorchModeInternal(sensor, sensor, TorchModeStatusNotAvailable, FALSE);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// HAL3Module::ReleaseTorchForCamera
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID HAL3Module::ReleaseTorchForCamera(
    UINT32 logicalCameraId,
    UINT32 fwNotificationId)
{
    CAMX_ASSERT(logicalCameraId < m_numLogicalCameras);
    CAMX_UNREFERENCED_PARAM(fwNotificationId);

    // Make sure all flash lights are released
    for (UINT32 sensor = 0; sensor < m_numLogicalCameras; sensor++)
    {
        CAMX_ASSERT(TorchModeStatusNotAvailable == m_torchStatus[sensor]);
        SetTorchModeInternal(sensor, sensor, TorchModeStatusAvailableOff, TRUE);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// HAL3Module::InitConfigurationForTorch
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID HAL3Module::InitConfigurationForTorch(
    UINT32 cameraId,
    Camera3StreamConfig *pStreamConfigs)
{
    CAMX_ASSERT(pStreamConfigs != NULL);

    CHIAppCallbacks *pCHIAppCallbacks = HAL3Module::GetInstance()->GetCHIAppCallbacks();

    /// @todo (CAMX-1518) Handle private data from Override module
    VOID *pPrivateData;
    BOOL isOverrideEnabled = FALSE;
    Camera3Stream *pTotalStreams[1];
    CamxResult result = CamxResultSuccess;

    ChiOverrideExtendOpen extend = {0};
    ChiOverrideToken tokenList[NumExtendSettings] = {{0}};
    extend.pTokens = tokenList;

    GenerateExtendOpenData(NumExtendSettings, &extend);

    // Reserve the camera to detect if it is already open or too many concurrent are open
    result = HAL3Module::GetInstance()->ProcessCameraOpen(cameraId, &extend);

    if (CamxResultSuccess == result)
    {

        // Sample code to show how the VOID* can be used in ModifySettings
        ChiOverrideModifySetting setting[NumExtendSettings] = {{{0}}};
        GenerateModifySettingsData(setting);

        /*
         * We are using setting 8 and 9 only because for torch mode usecase, we do not want other
         * override settings to be used, but just to modify the open and close status of the camera
         * or else torch mode will fail because other settings change the usecase selection logic
         */
        HAL3Module::GetInstance()->GetCHIAppCallbacks()->CHIModifySettings(&setting[8]); // overrride close
        HAL3Module::GetInstance()->GetCHIAppCallbacks()->CHIModifySettings(&setting[9]); // override open

        // Create a dummy streams configuration for Torch case.
        m_torchStream.streamType = StreamTypeOutput;
        m_torchStream.width = 640;
        m_torchStream.height = 480;
        m_torchStream.format = HALPixelFormatYCbCr420_888;
        m_torchStream.dataspace = HALDataspaceUnknown;
        m_torchStream.rotation = StreamRotationCCW0;
        m_torchStream.grallocUsage = 0;
        m_torchStream.maxNumBuffers = 0;
        m_torchStream.pPrivateInfo = NULL;

        pTotalStreams[0] = &m_torchStream;

        pStreamConfigs->numStreams = 1;
        pStreamConfigs->operationMode = StreamConfigModeQTITorchWidget;
        pStreamConfigs->ppStreams = reinterpret_cast<Camera3Stream **>(&pTotalStreams);

        CamX::Utils::Memset(&m_camera3Device, 0, sizeof(m_camera3Device));

        pCHIAppCallbacks->CHIInitializeOverrideSession(cameraId,
                                                       &m_camera3Device,
                                                       NULL,
                                                       pStreamConfigs,
                                                       &isOverrideEnabled,
                                                       &pPrivateData);
    }

    if (CamxResultSuccess == result)
    {
        // Create metadata needed for Torch.Need this to update the metadata while submitting the request.
        // NOWHINE CP036a: exception, as this is internal metadata.
        m_pMetadata = const_cast<Metadata *>(HAL3DefaultRequest::ConstructDefaultRequestSettings(cameraId, RequestTemplatePreview));
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// HAL3Module::DeInitConfigurationForTorch
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID HAL3Module::DeInitConfigurationForTorch(
    UINT32 cameraId)
{
    CAMX_UNREFERENCED_PARAM(cameraId);

    ChiOverrideExtendClose extend = {0};
    ChiOverrideToken tokenList[NumExtendSettings] = {{0}};
    extend.pTokens = tokenList;
    GenerateExtendCloseData(NumExtendSettings, &extend);

    HAL3Module::GetInstance()->ProcessCameraClose(cameraId, &extend);

    // Sample code to show how the VOID* can be used in ModifySettings
    ChiOverrideModifySetting setting[NumExtendSettings] = {{{0}}};
    GenerateModifySettingsData(setting);
    /*
     * We are using setting 8 and 9 only because for torch mode usecase, we do not want other
     * override settings to be used, but just to modify the open and close status of the camera
     * or else torch mode will fail because other settings change the usecase selection logic
     */
    HAL3Module::GetInstance()->GetCHIAppCallbacks()->CHIModifySettings(&setting[8]); // overrride close
    HAL3Module::GetInstance()->GetCHIAppCallbacks()->CHIModifySettings(&setting[9]); // override open

    HAL3Module::GetInstance()->GetCHIAppCallbacks()->CHITeardownOverrideSession(&m_camera3Device, 0, NULL);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// HAL3Module::SubmitRequestForTorch
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID HAL3Module::SubmitRequestForTorch(
    UINT32 cameraId,
    TorchModeStatus torchStatus)
{

    CHIAppCallbacks *pCHIAppCallbacks = HAL3Module::GetInstance()->GetCHIAppCallbacks();
    Camera3CaptureRequest tempCaptureRequest;
    CamxResult result = CamxResultSuccess;
    FlashModeValues flashMode = FlashModeOff;

    CAMX_UNREFERENCED_PARAM(cameraId);

    // Assign frame number 1 for On, 2 for Off
    if (TorchModeStatusAvailableOn == torchStatus)
    {
        flashMode = FlashModeTorch;
        result = HAL3MetadataUtil::SetMetadata(m_pMetadata, FlashMode,
                                               reinterpret_cast<VOID *>(&(flashMode)),
                                               1);
        tempCaptureRequest.frameworkFrameNum = 1;
    }
    else if (TorchModeStatusAvailableOff == torchStatus ||
             TorchModeStatusNotAvailable == torchStatus)
    {
        flashMode = FlashModeOff;
        result = HAL3MetadataUtil::SetMetadata(m_pMetadata, FlashMode,
                                               reinterpret_cast<VOID *>(&(flashMode)),
                                               1);
        tempCaptureRequest.frameworkFrameNum = 2;
    }
    tempCaptureRequest.pMetadata = m_pMetadata;
    tempCaptureRequest.pInputBuffer = NULL;
    tempCaptureRequest.pOutputBuffers = NULL;
    tempCaptureRequest.numOutputBuffers = 1;

    result = pCHIAppCallbacks->CHIOverrideProcessRequest(&m_camera3Device, &tempCaptureRequest, NULL);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// HAL3Module::SetTorchModeInternal
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID HAL3Module::SetTorchModeInternal(
    UINT32 logicalCameraId,
    UINT32 fwNotificationId,
    TorchModeStatus torchStatus,
    BOOL inReleaseMode)
{
    CAMX_ASSERT(logicalCameraId < m_numLogicalCameras);

    // Don't change status if status didn't change
    if (torchStatus != m_torchStatus[logicalCameraId])
    {
        switch (torchStatus)
        {
        // Turn the torch off or move to not available
        case TorchModeStatusNotAvailable:
        case TorchModeStatusAvailableOff:
            // Nothing to do if changing from off or not available
            if (TorchModeStatusAvailableOn == m_torchStatus[logicalCameraId])
            {
                /// @todo (CAMX-265) Turn off
                SubmitRequestForTorch(logicalCameraId, torchStatus);
                /// @todo (CAMX-265) De-init
                DeInitConfigurationForTorch(logicalCameraId);
            }
            break;
        // Turn the torch on
        case TorchModeStatusAvailableOn:
            // Should never change from not available to on (should be caught by upper layers)
            CAMX_ASSERT(TorchModeStatusNotAvailable != m_torchStatus[logicalCameraId]);
            // Nothing to do if changing from on
            if (TorchModeStatusAvailableOff == m_torchStatus[logicalCameraId])
            {
                /// @todo (CAMX-265) Init
                // Setup configure streams needed for Torch mode.
                Camera3StreamConfig streamConfigs;
                InitConfigurationForTorch(logicalCameraId, &streamConfigs);
                /// @todo (CAMX-265) Turn on
                SubmitRequestForTorch(logicalCameraId, torchStatus);
            }
            break;
        default:
            CAMX_ASSERT_ALWAYS_MESSAGE("Invalid torch status: %x", static_cast<UINT32>(torchStatus));
            break;
        }
        m_torchStatus[logicalCameraId] = torchStatus;

        /// @todo (CAMX-265) If no flash, skip callback.  Also, don't pass the CB pointer into the HAL3Module,
        ///                  instead call back into the camxhal3 static functions and insert the frameworkId
        ///                  there (and get rid of frameworkId in the torch calls...)
        CAMX_LOG_INFO(CamxLogGroupHAL,
                      "Torch notify state is (inReleaseMode = %d, dropCallbacks = %d)",
                      inReleaseMode,
                      m_dropCallbacks);

        if ((NULL != m_pModuleCbs) &&
            ((FALSE == inReleaseMode) || (FALSE == m_dropCallbacks)))
        {
            CHAR cameraIdString[8];
            OsUtils::SNPrintF(cameraIdString, sizeof(cameraIdString), "%d", fwNotificationId);
            m_pModuleCbs->TorchModeStatusChange(m_pModuleCbs, cameraIdString, torchStatus);
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HAL3Module::Dump
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID HAL3Module::Dump(
    INT fd) const
{
    CAMX_UNREFERENCED_PARAM(fd);
    // nothing worth dumping in here
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HAL3Module::HAL3Module
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HAL3Module::HAL3Module()
{
    CamxResult result = CamxResultSuccess;

    CAMX_LOG_DEBUG(CamxLogGroupHAL, "***************************************************");
    CAMX_LOG_DEBUG(CamxLogGroupHAL, "SHA1:     %s", CAMX_SHA1);
    CAMX_LOG_DEBUG(CamxLogGroupHAL, "COMMITID: %s", CAMX_COMMITID);
    CAMX_LOG_DEBUG(CamxLogGroupHAL, "BUILD TS: %s", CAMX_BUILD_TS);
    CAMX_LOG_DEBUG(CamxLogGroupHAL, "***************************************************");

    m_hChiOverrideModuleHandle = NULL;
    m_numLogicalCameras = 0;
    m_pStaticSettings = HwEnvironment::GetInstance()->GetStaticSettings();

    CAMX_ASSERT(CamxResultSuccess == result);

    CamX::Utils::Memset(&m_ChiAppCallbacks, 0, sizeof(m_ChiAppCallbacks));

    for (UINT32 sensor = 0; sensor < MaxNumImageSensors; sensor++)
    {
        m_torchStatus[sensor] = TorchModeStatusAvailableOff;
    }
    m_pMetadata = NULL;

    static const UINT NumCHIOverrideModules = 1;

    UINT16 fileCount = 0;

    CHAR moduleFileName[FILENAME_MAX];

    CAMX_LOG_WARN(CamxLogGroupHAL, "Searching for Chi Override module in folder: %s", CHIOverrideModulePath);

    fileCount = OsUtils::GetFilesFromPath(CHIOverrideModulePath,
                                          FILENAME_MAX,
                                          &moduleFileName[0],
                                          "*",
                                          "chi",
                                          "*",
                                          &SharedLibraryExtension[0]);

    if (0 == fileCount)
    {
        CAMX_LOG_INFO(CamxLogGroupHAL, "FATAL: No CHI Module library found in %s - Cannot proceed", CHIOverrideModulePath);
    }
    else
    {
        if (NumCHIOverrideModules == fileCount)
        {
            CAMX_LOG_WARN(CamxLogGroupHAL, "1 CHI Module library found - %s and trying to open it", &moduleFileName[0]);

            m_hChiOverrideModuleHandle = OsUtils::LibMap(&moduleFileName[0]);

            if (NULL != m_hChiOverrideModuleHandle)
            {
                CAMX_LOG_WARN(CamxLogGroupHAL, "CHI Module library successfully opened");

                CHIHALOverrideEntry funcCHIHALOverrideEntry =
                    reinterpret_cast<CHIHALOverrideEntry>(
                        CamX::OsUtils::LibGetAddr(m_hChiOverrideModuleHandle, "chi_hal_override_entry"));

                if (NULL != funcCHIHALOverrideEntry)
                {
                    funcCHIHALOverrideEntry(&m_ChiAppCallbacks);

                    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIGetNumCameras);
                    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIGetCameraInfo);
                    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIFinalizeOverrideSession);
                    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIInitializeOverrideSession);
                    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIOverrideProcessRequest);
                    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIOverrideFlush);
                    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHITeardownOverrideSession);
                    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIExtendOpen);
                    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIExtendClose);
                    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIRemapCameraId);
                    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIModifySettings);

                    if ((NULL != m_ChiAppCallbacks.CHIGetNumCameras) &&
                        (NULL != m_ChiAppCallbacks.CHIGetCameraInfo) &&
                        (NULL != m_ChiAppCallbacks.CHIFinalizeOverrideSession) &&
                        (NULL != m_ChiAppCallbacks.CHIInitializeOverrideSession) &&
                        (NULL != m_ChiAppCallbacks.CHIOverrideProcessRequest) &&
                        (NULL != m_ChiAppCallbacks.CHIOverrideFlush) &&
                        (NULL != m_ChiAppCallbacks.CHITeardownOverrideSession) &&
                        (NULL != m_ChiAppCallbacks.CHIExtendOpen) &&
                        (NULL != m_ChiAppCallbacks.CHIExtendClose) &&
                        (NULL != m_ChiAppCallbacks.CHIRemapCameraId) &&
                        (NULL != m_ChiAppCallbacks.CHIModifySettings))
                    {
                        CAMX_LOG_WARN(CamxLogGroupHAL, "CHI Module library function pointers exchanged");
                    }
                }
            }
            else
            {
                CAMX_LOG_ERROR(CamxLogGroupHAL, "Couldn't open CHI Module lib. All usecases will go thru HAL implementation");
            }
        }
        else
        {
            if (fileCount > 1)
            {
                CAMX_LOG_ERROR(CamxLogGroupHAL, "Cannot have more than one CHI override module present", fileCount);
            }
        }
    }

    if (NULL != m_ChiAppCallbacks.CHIGetNumCameras)
    {
        m_ChiAppCallbacks.CHIGetNumCameras(&m_numFwCameras, &m_numLogicalCameras);
    }
    else
    {
        CAMX_ASSERT_ALWAYS_MESSAGE("Override module is mandatory.  Returning 0 cameras, and app will not behave properly");
        m_numFwCameras = 0;
    }

    // There are arrays capped with a max number of sensors.  If there are more than MaxNumImageSensors logical
    // cameras, this assert will fire.
    CAMX_ASSERT(m_numLogicalCameras < MaxNumImageSensors);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HAL3Module::~HAL3Module
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HAL3Module::~HAL3Module()
{
    if (NULL != m_hChiOverrideModuleHandle)
    {
        OsUtils::LibUnmap(m_hChiOverrideModuleHandle);
        m_hChiOverrideModuleHandle = NULL;
    }
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// HAL3Module::ProcessCameraOpen
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult HAL3Module::ProcessCameraOpen(
    UINT32 logicalCameraId,
    VOID *pPriv)
{
    CamxResult result = CamxResultSuccess;

    m_ChiAppCallbacks.CHIExtendOpen(logicalCameraId, pPriv);

    if (logicalCameraId >= m_numLogicalCameras)
    {
        CAMX_LOG_ERROR(CamxLogGroupHAL, "Invalid logical camera id: %d", logicalCameraId);
        result = CamxResultEInvalidArg;
    }
    else if (TRUE == m_perCameraInfo[logicalCameraId].isCameraOpened)
    {
        CAMX_LOG_ERROR(CamxLogGroupHAL, "Camera id already in use: %d", logicalCameraId);
        result = CamxResultEBusy;
    }
    else if ((m_numCamerasOpened + 1) > MaxConcurrentDevices)
    {
        CAMX_LOG_ERROR(CamxLogGroupHAL, "Too many concurrent devices to open camera id: %d", logicalCameraId);
        result = CamxResultETooManyUsers;
    }
    else
    {
        m_perCameraInfo[logicalCameraId].isCameraOpened = TRUE;
        m_numCamerasOpened++;
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// HAL3Module::ProcessCameraClose
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult HAL3Module::ProcessCameraClose(
    UINT32 logicalCameraId,
    VOID *pPriv)
{
    CamxResult result = CamxResultSuccess;

    m_ChiAppCallbacks.CHIExtendClose(logicalCameraId, pPriv);

    if (m_numLogicalCameras <= logicalCameraId)
    {
        CAMX_LOG_ERROR(CamxLogGroupHAL, "Invalid camera id: %d", logicalCameraId);
        result = CamxResultEInvalidArg;
    }
    else if (FALSE == m_perCameraInfo[logicalCameraId].isCameraOpened)
    {
        CAMX_LOG_ERROR(CamxLogGroupHAL, "Camera id is closed already: %d", logicalCameraId);
        result = CamxResultEBusy;
    }
    else
    {
        m_perCameraInfo[logicalCameraId].isCameraOpened = FALSE;
        m_numCamerasOpened--;
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HAL3Module::GetNumCameras
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT32 HAL3Module::GetNumCameras() const
{
    return m_numFwCameras;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HAL3Module::GetCameraInfo
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult HAL3Module::GetCameraInfo(
    UINT32 logicalCameraId,
    CameraInfo *pCameraInfo) const
{
    CamxResult result = CamxResultSuccess;
    ChiCameraInfo chiCameraInfo = {0};

    chiCameraInfo.pLegacy = pCameraInfo;

    if (NULL != m_ChiAppCallbacks.CHIGetCameraInfo)
    {
        result = m_ChiAppCallbacks.CHIGetCameraInfo(logicalCameraId, pCameraInfo);
    }
    else
    {
        result = CamxResultEFailed;
        CAMX_ASSERT_ALWAYS_MESSAGE("CHI override module is not present!");
    }

    return result;
}

CAMX_NAMESPACE_END
